package com.coderman.common.starter.logparam.aspect;


import com.coderman.common.starter.logparam.annotations.InnerBusLog;
import com.coderman.common.starter.logparam.beans.InnerBusLogBean;
import com.coderman.common.starter.logparam.context.InnerBusLogicContext;
import com.coderman.common.starter.logparam.service.logparams.LogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Map;

/**
 * @Author fanchunshuai
 * @Date 2019/4/24 19
 * @Description: 内部服务方法打印
 * 入参，出参，执行时间
 */
@Component
@Aspect
@Order(value = 1)
public class InnerBusLogAspect {

    @Resource
    private InnerBusLogicContext innerBusLogicContext;

    /**
     * 方法执行的时间监控
     * 下面这种用Map的形式是线程不安全的，会导致统计耗时错误，比如一个事务方法1ms执行完毕
     * private Map<Integer, Long> methodExeTimeMap = new HashMap<>(256);
     */
    private static final ThreadLocal<Long> localStartUseTime = new ThreadLocal<>();

    @Resource
    private LogService logParamHelperService;

    /**
     * 在接口方法执行之前记录日志
     *
     * @throws Throwable
     */
    @Before("@annotation(innerBusLog)")
    public void exeTimeStart(JoinPoint joinPoint, InnerBusLog innerBusLog) throws Throwable {
        Map innerContextMap = innerBusLogicContext.getInnerContextMap(joinPoint);
        if (innerContextMap.isEmpty()) {
            return;
        }
        InnerBusLogBean innerBusLogBean = (InnerBusLogBean) innerContextMap.get("innerBusLogBean");

        //如果需要记录方法执行时间
        if (innerBusLogBean.isExeTime() == true) {
            localStartUseTime.set(System.currentTimeMillis());
        }
        //如果需要打印入参
        if (innerBusLogBean.isLogInParam() == true) {
            String tmpKey = innerContextMap.get("tmpKey").toString();
            logParamHelperService.logInputParam(joinPoint.getArgs(), tmpKey);
        }
    }


    /**
     * 在接口方法执行之后录开始时间
     *
     * @throws Throwable
     */
    @AfterReturning(value = "@annotation(innerBusLog)", returning = "returnValue")
    public void exeTimeEnd(JoinPoint joinPoint, InnerBusLog innerBusLog, Object returnValue) throws Throwable {
        long endTime = System.currentTimeMillis();
        Map innerContextMap = innerBusLogicContext.getInnerContextMap(joinPoint);
        if (innerContextMap.isEmpty()) {
            return;
        }
        InnerBusLogBean innerBusLogBean = (InnerBusLogBean) innerContextMap.get("innerBusLogBean");
        //如果需要记录方法执行时间
        if (innerBusLogBean.isExeTime() == true) {
            String tmpKey = innerContextMap.get("tmpKey").toString();
            logParamHelperService.logExeTime(tmpKey, (endTime - localStartUseTime.get()), "inner");
            //防止内存溢出，用完需要及时remove掉
            localStartUseTime.remove();
        }
        //如果需要打印出参
        if (innerBusLogBean.isLogOutParam() == true) {
            if (returnValue == null) {
                return;
            }
            String tmpKey = innerContextMap.get("tmpKey").toString();
            logParamHelperService.logOutputParam(returnValue, tmpKey, "inner");
        }
    }

}
